﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Cms.Domain.Comparers;

namespace Cms.Domain
{
    [Serializable]
    public class Content : IAuditable
    {
        private IList<AdministratorGroup> _allowedAdministratorGroups;
        private IList<Category> _categories;
        private IList<Comment> _comments;
        private DateTime _created;
        private Administrator _createdBy;
        private IList<AdministratorGroup> _deniedAdministratorGroups;
        private IList<UserGroup> _deselectedUserGroups;
        private IList<DetailTemplateContentLink> _detailTemplates;
        private DateTime? _endPublishing;
        private DateTime? _eventEnd;
        private DateTime? _eventStart;
        private DateTime? _firstPublished;
        private int _id;
        private IList<MasterTemplateContentLink> _masterTemplates;
        private string _name;
        private IList<PageContentLink> _pages;
        private IList<UserGroup> _requiredUserGroups;
        private Site _site;
        private string _sortKey;
        private DateTime? _startPublishing;
        private IDictionary<int, ContentTranslation> _translations;

        public Content()
        {
            _translations = new Dictionary<int, ContentTranslation>();
            _pages = new List<PageContentLink>();
            _masterTemplates = new List<MasterTemplateContentLink>();
            _detailTemplates = new List<DetailTemplateContentLink>();
            _categories = new List<Category>();
            _created = DateTime.Now;
            _comments = new List<Comment>();
            _allowedAdministratorGroups = new List<AdministratorGroup>();
            _deniedAdministratorGroups = new List<AdministratorGroup>();
            _requiredUserGroups = new List<UserGroup>();
            _deselectedUserGroups = new List<UserGroup>();
        }
        
        public virtual int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        public virtual string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public virtual Site Site
        {
            get { return _site; }
            set { _site = value; }
        }
        
        public virtual IDictionary<int, ContentTranslation> Translations
        {
            get { return _translations; }
            set { _translations = value; }
        }

        public virtual IList<PageContentLink> Pages
        {
            get { return _pages; }
            set { _pages = value; }
        }
        
        public virtual IList<MasterTemplateContentLink> MasterTemplates
        {
            get { return _masterTemplates; }
            set { _masterTemplates = value; }
        }
        
        public virtual IList<DetailTemplateContentLink> DetailTemplates
        {
            get { return _detailTemplates; }
            set { _detailTemplates = value; }
        }

        public virtual IList<Category> Categories
        {
            get { return _categories; }
            set { _categories = value; }
        }
        
        public virtual DateTime? FirstPublished
        {
            get { return _firstPublished; }
            set { _firstPublished = value; }
        }

        public virtual DateTime? EventStart
        {
            get { return _eventStart; }
            set { _eventStart = value; }
        }
        
        public virtual DateTime? EventEnd
        {
            get { return _eventEnd; }
            set { _eventEnd = value; }
        }
        
        public virtual string SortKey
        {
            get { return _sortKey; }
            set { _sortKey = value; }
        }
        
        public virtual DateTime? StartPublishing
        {
            get { return _startPublishing; }
            set { _startPublishing = value; }
        }
        
        public virtual DateTime? EndPublishing
        {
            get { return _endPublishing; }
            set { _endPublishing = value; }
        }
        
        public virtual DateTime Created
        {
            get { return _created; }
            set { _created = value; }
        }

        public virtual Administrator CreatedBy
        {
            get { return _createdBy; }
            set { _createdBy = value; }
        }
        
        public virtual IList<Comment> Comments
        {
            get { return _comments; }
            set { _comments = value; }
        }
        
        public virtual IList<AdministratorGroup> AllowedAdministratorGroups
        {
            get { return _allowedAdministratorGroups; }
            set { _allowedAdministratorGroups = value; }
        }
        
        public virtual IList<AdministratorGroup> DeniedAdministratorGroups
        {
            get { return _deniedAdministratorGroups; }
            set { _deniedAdministratorGroups = value; }
        }
        
        public virtual IList<UserGroup> RequiredUserGroups
        {
            get { return _requiredUserGroups; }
            set { _requiredUserGroups = value; }
        }

        public virtual IList<UserGroup> DeselectedUserGroups
        {
            get { return _deselectedUserGroups; }
            set { _deselectedUserGroups = value; }
        }
        
        public virtual string GetPublishedHtml(int localeID)
        {
            return !_translations.ContainsKey(localeID) ? string.Empty : _translations[localeID].GetPublishedHtml();
        }

        public virtual string GetPublishedTitle(int localeID)
        {
            return !_translations.ContainsKey(localeID) ? string.Empty : _translations[localeID].GetPublishedTitle();
        }

        public virtual string GetHtml(int localeID, string timestamp)
        {
            return !_translations.ContainsKey(localeID) ? string.Empty : _translations[localeID].GetHtml(timestamp);
        }
        
        public virtual string GetTitle(int localeID, string timestamp)
        {
            return !_translations.ContainsKey(localeID) ? string.Empty : _translations[localeID].GetTitle(timestamp);
        }
        
        public virtual ContentTranslationVersion AddVersion(Locale locale, long timestamp, string html, string title, Administrator author)
        {
            ContentTranslation translation;
            if (!_translations.ContainsKey(locale.ID))
            {
                translation = new ContentTranslation { Content = this, Locale = locale };
                _translations.Add(locale.ID, translation);
            }
            else
                translation = _translations[locale.ID];
            var ctv = new ContentTranslationVersion
                          {
                              Translation = translation,
                              Timestamp = timestamp.ToString(),
                              Html = html,
                              Title = title,
                              Author = author
                          };
            translation.Versions.Add(ctv);
            return ctv;
        }
        
        public virtual ContentTranslation GetTranslation(int localeID)
        {
            return _translations.ContainsKey(localeID) ? _translations[localeID] : new ContentTranslation();
        }
        
        public virtual IList<ContentSetContainer> GetContainers()
        {
            IList<ContentSetContainer> containers = new List<ContentSetContainer>();
            foreach (PageContentLink pageLink in _pages)
                containers.Add(pageLink.Page);
            foreach (MasterTemplateContentLink masterTemplateLink in _masterTemplates)
                containers.Add(masterTemplateLink.MasterTemplate);
            foreach (DetailTemplateContentLink detailTemplateLink in _detailTemplates)
                containers.Add(detailTemplateLink.DetailTemplate);
            return containers;
        }
        
        public virtual void RemovePage(Page page)
        {
            IList<PageContentLink> links = _pages.Where(pl => pl.Page.ID == page.ID).ToList();
            foreach (PageContentLink pl in links)
            {
                _pages.Remove(pl);
                pl.Page.Content.Remove(pl);
            }
        }

        public virtual void RemoveMasterTemplate(MasterTemplate mt)
        {
            IList<MasterTemplateContentLink> links =
                _masterTemplates.Where(mtl => mtl.MasterTemplate.ID == mt.ID).ToList();
            foreach (MasterTemplateContentLink mtl in links)
            {
                _masterTemplates.Remove(mtl);
                mtl.MasterTemplate.Content.Remove(mtl);
            }
        }

        public virtual void RemoveDetailTemplate(DetailTemplate dt)
        {
            IList<DetailTemplateContentLink> links =
                _detailTemplates.Where(dtl => dtl.DetailTemplate.ID == dt.ID).ToList();
            foreach (DetailTemplateContentLink dtl in links)
            {
                _detailTemplates.Remove(dtl);
                dtl.DetailTemplate.Content.Remove(dtl);
            }
        }
        
        public virtual IList<ContentTranslationVersion> GetVersions(int localeID)
        {
            if (!_translations.ContainsKey(localeID))
                return new List<ContentTranslationVersion>();
            List<ContentTranslationVersion> versions = _translations[localeID].Versions.ToList();
            versions.Sort(new ContentTranslationVersionComparer(SortDirection.Descending, ContentTranslationVersionSortMode.Timestamp));
            return versions;
        }

        public virtual bool IsInCategory(int categoryId)
        {
            return _categories.Any(category => category.ID == categoryId);
        }

        public virtual bool IsPublishedNow()
        {
            return
                !((_startPublishing.HasValue && _startPublishing.Value > DateTime.Now) ||
                  (_endPublishing.HasValue && _endPublishing.Value < DateTime.Now));
        }

        public virtual bool HasPublishedVersion(int localeID)
        {
            ContentTranslation ct = GetTranslation(localeID);
            return ct != null && ct.PublishedVersion != null;
        }

        public static bool ContainsPageBreak(string html)
        {
            return html.IndexOf("<!-- pagebreak -->") > 0;
        }

        public static string TruncateAfterPageBreak(string html)
        {
            if (ContainsPageBreak(html))
            {
                html = html.Substring(0, html.IndexOf("<!-- pagebreak -->"));
                var openingParagraphTagMatches = Regex.Matches(html, @"(<p)([\s]+[\w]+=((""[^""]*"")|('[^']*')))*([\s]*>)");
                var closingParagraphTagMatches = Regex.Matches(html, "</p>");
                if (openingParagraphTagMatches.Count <= closingParagraphTagMatches.Count)
                {
                    return html;
                }
                for (var i = 0; i < openingParagraphTagMatches.Count - closingParagraphTagMatches.Count; i++)
                {
                    html += "</p>";
                }
                return html;
            }
            return html;
        }

        public static string ReplaceVirtualUrlsWithAbsoluteUrls(string html, Site site)
        {
            string regex = "(<a[^>]+href=\")(?!http)(/{0,1})([^\"]+)(\")";
            html = Regex.Replace(html, regex, "$1http://" + site.Domain + "/$3$4", RegexOptions.IgnoreCase); 
            regex = "(<img[^>]+src=\")(?!http)(/{0,1})([^\"]+)(\")";
            return Regex.Replace(html, regex, "$1http://" + site.Domain + "/$3$4", RegexOptions.IgnoreCase); 
        }

        public static string RemoveImgTags(string html)
        {
            return Regex.Replace(html, @"(<img)([\s]+[\w]+=((""[^""]*"")|('[^']*')))*([\s]*/>)", "", RegexOptions.IgnoreCase);
        }

        #region IAuditable Members

        public virtual string GetState()
        {
            return "Created = " + _created +
                   ", CreatedByID = " + _createdBy.ID +
                   ", Name = " + _name +
                   ", SiteID = " + _site.ID +
                   ", SortKey = " + _sortKey +
                   ", StartPublishing = " + (_startPublishing.HasValue ? _startPublishing.Value.ToString() : "NULL") +
                   ", EndPublishing = " + (_eventEnd.HasValue ? _eventEnd.Value.ToString() : "NULL") +
                   ", EventStart = " + (_endPublishing.HasValue ? _endPublishing.Value.ToString() : "NULL") +
                   ", EventEnd = " + (_eventStart.HasValue ? _eventStart.Value.ToString() : "NULL") +
                   ", FirstPublished = " + (_firstPublished.HasValue ? _firstPublished.Value.ToString() : "NULL");
        }

        #endregion
    }
}